package com.hisoft.entity;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.hisoft.exception.XpathNotFoundException;
import com.hisoft.type.DeviceState;
import com.hisoft.type.XMLType;
import com.hisoft.utility.CommonTool;
//import com.hisoft.utility.NetSpeed;
import com.hisoft.xml.Dom4JXMLHelper;
import com.hisoft.xml.SchemaChecker;

public class Environment {
	Logger logger = Logger.getLogger(Environment.class);
	// 默认的config文件
	private static String CONFIGFILEPATH = "config.xml";
	private final static String CONFIGXPATH = "/configs/";
	private final static String ACCOUNTBASEXPATH = "/info/accounts/account";
	private final static String TESTCASEPATH = "testCasePath";

	private String host;
	private int port;
	private String baseUrl;
	private String browser;
	private String language;
	private String timeout;
	private String os = null;
	

	private List<File> testCaseList;
	private String testCasePath;
	private String pageDataPath;
	private String accountFilePath;
	private String setemailInfoFilePath;
	//add by john 2011-11-15
	private String lanSpeed;
	private String wanSpeed;
	private String urlSpeed;
	

	public String getLanSpeed() {
		return lanSpeed;
	}

	public void setLanSpeed(String lanSpeed) {
		this.lanSpeed = lanSpeed;
	}

	public String getWanSpeed() {
		return wanSpeed;
	}

	public void setWanSpeed(String wanSpeed) {
		this.wanSpeed = wanSpeed;
	}

	public String getUrlSpeed() {
		return urlSpeed;
	}

	public void setUrlSpeed(String urlSpeed) {
		this.urlSpeed = urlSpeed;
	}

	public String getEmailInfoFilePath() {
		return setemailInfoFilePath;
	}

	public void setEmailInfoFilePath(String emailInfoFilePath) {
		this.setemailInfoFilePath = emailInfoFilePath;
	}

	private int retryTimes;
	private Map<String, AccountEntity> accountMap;
	// 单例模式
	private static Environment environment = null;

	// 初始化environment
	private Environment() {
		logger.info("initializing Environment ... ");
		SAXReader saxReader = new SAXReader();
		if (SchemaChecker.validateXml(CONFIGFILEPATH, XMLType.CONFIG)) {
			try {
				Document document = saxReader.read(new File(CONFIGFILEPATH));
				// host = document.selectSingleNode(CONFIGXPATH +
				// "host").getText();
				this.setHost(document.selectSingleNode(CONFIGXPATH + "host").getText());
				// port = Integer.parseInt(document.selectSingleNode(CONFIGXPATH
				// + "port").getText());
				this.setPort(Integer.parseInt(document.selectSingleNode(CONFIGXPATH + "port").getText()));
				// baseUrl = document.selectSingleNode(CONFIGXPATH +
				// "baseUrl").getText();
				this.setBaseUrl(document.selectSingleNode(CONFIGXPATH + "baseUrl").getText());
				// browser = document.selectSingleNode(CONFIGXPATH +
				// "browser").getText();
				this.setBrowser(document.selectSingleNode(CONFIGXPATH + "browser").getText());
				// language = document.selectSingleNode(CONFIGXPATH +
				// "language").getText();
				this.setLanguage(document.selectSingleNode(CONFIGXPATH + "language").getText());
				// timeout = document.selectSingleNode(CONFIGXPATH +
				// "timeout").getText();
				this.setTimeout(document.selectSingleNode(CONFIGXPATH + "timeout").getText());
				// retryTimes =
				// Integer.parseInt(document.selectSingleNode(CONFIGXPATH +
				// "retryTimes").getText());
				this.setRetryTimes(Integer.parseInt(document.selectSingleNode(CONFIGXPATH + "retryTimes").getText()));
				// pageDataPath = document.selectSingleNode(CONFIGXPATH +
				// "pageDataPath").getText();
				this.setPageDataPath(document.selectSingleNode(CONFIGXPATH + "pageDataPath").getText());
				// accountFilePath = document.selectSingleNode(CONFIGXPATH +
				// "accountFile").getText();
				this.setAccountFilePath(document.selectSingleNode(CONFIGXPATH + "accountFile").getText());
				this.setEmailInfoFilePath(document.selectSingleNode(CONFIGXPATH + "emailInfoFile").getText());
				// accountMap = ReadAccountMap(accountFilePath);
				this.setAccountMap(ReadAccountMap(accountFilePath));
				// testCaseList = getTestCaseList(document);
				this.setTestCaseList(getTestCaseList(document));
				Node node = (Node) document.selectSingleNode(CONFIGXPATH + "testCasePath");
				// testCasePath = node.valueOf("@name");
				this.setTestCasePath(node.valueOf("@name"));
				
				//get test net download speed
				//this.setLanSpeed(NetSpeed.getLocalSpeed());
				//this.setWanSpeed(NetSpeed.getAvgSpeed());
				//this.setUrlSpeed(NetSpeed.getSpeed(this.baseUrl,1000)+"KB/s");
				
			} catch (DocumentException ex) {
				logger.error(ex.getMessage(), ex);
			} catch (XpathNotFoundException e) {
				logger.error(e.getMessage(), e);
			}
		} else {
			logger.error("There some unknow error in file'" + CONFIGFILEPATH + "'");
		}
		logger.info("initializing Environment ... OK");
	}

	/**
	 * singleton model
	 * 如果Environment==null则实例化一个对象，
	 * 返回Environment对象
	 * <b></b><br/>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-8-30
	 */
	public static Environment getInstance() {
		if (null == environment) {
			environment = new Environment();
		}
		return environment;
	}

	/**
	 * 获得testcase的list
	 * 
	 * @param document
	 * @return
	 * @throws XpathNotFoundException
	 */
	private List<File> getTestCaseList(Document document) throws XpathNotFoundException {
		List<File> allList = new ArrayList<File>();
		String baseXpath = CONFIGXPATH + TESTCASEPATH;
		List<?> objList = document.selectNodes(baseXpath);
		for (Object obj : objList) {
			allList.addAll(getTestCaseListForOneNode((Node) obj, baseXpath));
		}
		return allList;
	}

	/**
	 * 获得testcase的list
	 * 
	 * @param node
	 * @param baseXpath
	 * @return
	 * @throws XpathNotFoundException
	 */
	private List<File> getTestCaseListForOneNode(Node node, String baseXpath) throws XpathNotFoundException {
		// String baseXpath = CONFIGXPATH + "testCasePath";
		// Node node = (Node)document.selectSingleNode(baseXpath);
		String type = node.valueOf("@type");
		String path = node.valueOf("@name");
		List<File> lists = new ArrayList<File>();

		// TODO:
		switch (TestCasePathType.valueOf(type)) {
		case file:
			lists = CommonTool.readXmlFileList(path);
			break;
		case exclude:
			String excludeXpath = baseXpath + "/exclude";
			lists = CommonTool.readXmlFileList(path);
			List<File> excludeFileList = new ArrayList<File>();
			List<String> excludeTextList = Dom4JXMLHelper.getTextList(excludeXpath, CONFIGFILEPATH);

			for (String aPath : excludeTextList) {
				File file = new File(aPath);
				if (!file.exists())
					throw new RuntimeException("The path: " + aPath + " in the config file is not exist!");
				if (file.isDirectory()) {
					/*
					 * if exclude file is a dictionary, exclude all the file
					 */
					List<File> tempList = CommonTool.readXmlFileList(aPath);
					for (File tempFile : tempList) {
						excludeFileList.add(tempFile);
					}
				} else {
					/*
					 * if exclude file is only a file
					 */
					excludeFileList.add(file);
				}
			}

			for (File excludeFile : excludeFileList) {
				for (File file : lists) {
					if (excludeFile.getPath().equals(file.getPath())) {
						lists.remove(file);
						break;
					}
				}
			}
			break;
		case include:
			String includeXpath = baseXpath + "/include";
			List<?> includeList = Dom4JXMLHelper.readNodeList(includeXpath, CONFIGFILEPATH);
			for (Object obj : includeList) {
				String aPath = ((Node) obj).getText();
				File file = new File(aPath);
				if (!file.exists())
					throw new RuntimeException("The path: " + aPath + " in the config file is not exist!");

				if (file.isDirectory()) {
					/*
					 * if ixclude file is a dictionary, exclude all the file
					 */
					List<File> tempList = CommonTool.readXmlFileList(aPath);
					for (File tempFile : tempList) {
						lists.add(tempFile);
					}
				} else {
					/*
					 * if include file is only a file
					 */
					lists.add(file);
				}
			}
			break;
		default:
			throw new RuntimeException();
		}
		return lists;
	}

	/**
	 * 
	 * @param filePath
	 * @return
	 * @throws XpathNotFoundException
	 * @throws DocumentException
	 */
	public Map<String, AccountEntity> ReadAccountMap(String filePath) throws XpathNotFoundException, DocumentException {

		List<?> accountList = Dom4JXMLHelper.readNodeList(ACCOUNTBASEXPATH, filePath);
		int accountCount = accountList.size();
		Map<String, AccountEntity> accountMap = new HashMap<String, AccountEntity>();

		for (int i = 0; i < accountCount; i++) {
			String accountType = ((Node) accountList.get(i)).valueOf("@type");
			accountMap.put(accountType, ReadAccount(filePath, accountType));
		}

		return accountMap;
	}

	/**
	 * 读取account数据
	 * 
	 * @param filePath
	 * @param accountType
	 * @return
	 * @throws XpathNotFoundException
	 */
	public AccountEntity ReadAccount(String filePath, String accountType) throws XpathNotFoundException {
		String xPath = ACCOUNTBASEXPATH + "[@type='" + accountType + "']";
		// login info
		String email = Dom4JXMLHelper.readSingleNode(xPath + "/email", filePath).getText();
		String passwd = Dom4JXMLHelper.readSingleNode(xPath + "/password", filePath).getText();
		String emailPasswd = Dom4JXMLHelper.readSingleNode(xPath + "/emailPassword", filePath).getText();
		String firstName = Dom4JXMLHelper.readSingleNode(xPath + "/firstName", filePath).getText();
		String lastName = Dom4JXMLHelper.readSingleNode(xPath + "/lastName", filePath).getText();

		// device info
		DeviceEntity device;
		List<DeviceEntity> devices = new ArrayList<DeviceEntity>();
		int deviceCount = 0;
		try {
			deviceCount = Dom4JXMLHelper.readNodeList(xPath + "/devices/device", filePath).size();
		} catch (XpathNotFoundException ex) {
		}

		for (int i = 0; i < deviceCount; i++) {
			device = new DeviceEntity();
			device.setDeviceName(((Node) Dom4JXMLHelper.readNodeList(xPath + "/devices/device/DeviceName", filePath).get(i)).getText());
			device.setModelName(((Node) Dom4JXMLHelper.readNodeList(xPath + "/devices/device/ModelName", filePath).get(i)).getText());
			device.setConnectType(((Node) Dom4JXMLHelper.readNodeList(xPath + "/devices/device/ConnectionType", filePath).get(i)).getText());
			device.setSn(((Node) Dom4JXMLHelper.readNodeList(xPath + "/devices/device/SN", filePath).get(i)).getText());
			device.setMac(((Node) Dom4JXMLHelper.readNodeList(xPath + "/devices/device/Mac", filePath).get(i)).getText());
			device.setUserName(((Node) Dom4JXMLHelper.readNodeList(xPath + "/devices/device/UserName", filePath).get(i)).getText());
			device.setPassWord(((Node) Dom4JXMLHelper.readNodeList(xPath + "/devices/device/Passwd", filePath).get(i)).getText());
			String state = (((Node) Dom4JXMLHelper.readNodeList(xPath + "/devices/device/state", filePath).get(i)).getText());
			device.setState(DeviceState.valueOf(state));
			device.setFw(((Node) Dom4JXMLHelper.readNodeList(xPath + "/devices/device/fw", filePath).get(i)).getText());
			devices.add(device);
		}
		return new AccountEntity(email, passwd, emailPasswd, firstName, lastName, devices);
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
		VariableMap.getInstance().mapPutKV("host", host);
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
		VariableMap.getInstance().mapPutKV("port", port);
	}

	public String getBaseUrl() {
		return baseUrl;
	}

	public void setBaseUrl(String baseUrl) {
		this.baseUrl = baseUrl;
		VariableMap.getInstance().mapPutKV("baseUrl", baseUrl);
	}

	public String getBrowser() {
		return browser;
	}

	public void setBrowser(String browser) {
		this.browser = browser;
		VariableMap.getInstance().mapPutKV("browser", browser);
	}

	public String getLanguage() {
		return language;
	}

	public void setLanguage(String language) {
		this.language = language;
		VariableMap.getInstance().mapPutKV("language", language);
	}

	public String getTimeout() {
		return timeout;
	}

	public void setTimeout(String timeout) {
		this.timeout = timeout;
		VariableMap.getInstance().mapPutKV("timeout", timeout);
	}

	public String getOs() {
		return os;
	}

	public void setOs(String os) {
		this.os = os;
		VariableMap.getInstance().mapPutKV("os", os);
	}

	/**
	 * 获得testcase的集合
	 * 
	 * <b></b><br/>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-8-30
	 */
	public List<File> getTestCaseList() {
		return testCaseList;
	}

	public void setTestCaseList(List<File> testCaseList) {
		this.testCaseList = testCaseList;
	}

	public String getTestCasePath() {
		return testCasePath;
	}

	public void setTestCasePath(String testCasePath) {
		this.testCasePath = testCasePath;
		VariableMap.getInstance().mapPutKV("testCasePath", testCasePath);
	}

	public String getPageDataPath() {
		return pageDataPath;
	}

	public void setPageDataPath(String pageDataPath) {
		this.pageDataPath = pageDataPath;
		VariableMap.getInstance().mapPutKV("pageDataPath", pageDataPath);
	}

	public String getAccountFilePath() {
		return accountFilePath;
	}

	public void setAccountFilePath(String accountFilePath) {
		this.accountFilePath = accountFilePath;
		VariableMap.getInstance().mapPutKV("accountFilePath", accountFilePath);
	}

	public int getRetryTimes() {
		return retryTimes;
	}

	public void setRetryTimes(int retryTimes) {
		this.retryTimes = retryTimes;
		VariableMap.getInstance().mapPutKV("retryTimes", retryTimes);
	}

	public Map<String, AccountEntity> getAccountMap() {
		return accountMap;
	}

	public void setAccountMap(Map<String, AccountEntity> accountMap) {
		this.accountMap = accountMap;
	}

	enum TestCasePathType {
		file, include, exclude
	}

	public static void setCONFIGFILEPATH(String cONFIGFILEPATH) {
		CONFIGFILEPATH = cONFIGFILEPATH;
	}

}
